import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.TreeSet;

import org.junit.Test;


public class SkipListMapTest {

	SkipListMap<Integer, Integer> sl;
	
	
	@Test
	public void testKeySimple() {
		sl = createAddOne();
		int test = sl.firstKey();
		assertEquals(test, 1);
		test = sl.lastKey();
		assertEquals(test, 1);
	}
	
	@Test
	public void testKey() {
		sl = createAddTen();
		assertEquals((int)sl.firstKey(), 0);
		assertEquals((int)sl.lastKey(), 9);
		
	}

	@Test
	public void testContains() {
		sl = createAddTen();
		for(int i = 0; i < 10; i++){
			assertTrue(sl.containsKey(i));
			assertTrue(sl.containsValue(i));
		}		
	}
	/*
	@Test(expected=IllegalArgumentException.class)
	public void testContainsKeyException(){
		SkipListMap<Integer, Integer> sl = new SkipListMap<Integer, Integer>(new CoinFlipper());
		sl.put(1, 1);
		assertTrue(sl.containsKey(null));
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testContainsValueException(){
		sl = createAddOne();
		assertTrue(sl.containsValue(null));
	}
*/
	@Test
	public void testPut() {
		sl = createAddOne();
		//System.out.println(sl.firstKey());
		assertEquals((int)sl.firstKey(), 1);
		assertEquals(sl.size(), 1);
		assertTrue(sl.containsKey(1));
		assertTrue(sl.containsValue(1));
		sl.put(1, 2);
		assertEquals((int)sl.firstKey(), 1);
		assertEquals(sl.size(), 1);
		assertTrue(sl.containsKey(1));
		assertFalse(sl.containsValue(1));
		assertTrue(sl.containsValue(2));
		sl.put(0, 0);
		assertEquals((int)sl.firstKey(), 0);
		assertEquals(sl.size(), 2);
		assertTrue(sl.containsKey(0));
		assertTrue(sl.containsValue(0));
		
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testPutNullKey(){
		sl = new SkipListMap<Integer, Integer>(new CoinFlipper());
		sl.put(null, 1);
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testPutNullValue(){
		sl = new SkipListMap<Integer, Integer>(new CoinFlipper());
		sl.put(1, null);
	}
	
	@Test
	public void testGet() {
		sl = createAddTen();
		System.out.println(sl.get(0));
		for(int i = 0; i < 10; i++){
			assertEquals((int)sl.get(i), i);
		}
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testGetNull(){
		sl = createAddOne();
		sl.get(null);
	}

	@Test
	public void testSize() {
		sl = createAddOne();
		assertEquals(sl.size(), 1);
		sl.put(0, 0);
		assertEquals(sl.size(), 2);
		sl.put(1, 0);
		assertEquals(sl.size(), 2);
		sl.remove(1);
		assertEquals(sl.size(), 1);
		sl.clear();
		assertEquals(sl.size(), 0);
	}

	@Test
	public void testClear() {
		sl = createAddOne();
		assertEquals(sl.size(), 1);
		sl.clear();
		assertEquals(sl.size(), 0);
		sl = createAddTen();
		assertEquals(sl.size(), 10);
		sl.clear();
		assertEquals(sl.size(), 0);
	}

	@Test
	public void testKeySet() {
		PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
		sl = new SkipListMap<Integer, Integer>(new CoinFlipper());
		int key;
		for(int i = 0; i < 10; i++){
			key = (int)(Math.random() * 100);
			sl.put(key, (int)(i * Math.random()));
			if(!pq.contains(key))
				pq.add(key);
		}
		TreeSet<Integer> set = (TreeSet<Integer>) sl.keySet();
		for(int i = 0; i < sl.size() + 1; i++){
			assertEquals(pq.poll(), set.pollFirst());
		}
	}

	@Test
	public void testValues() {
		sl = createAddTen();
		LinkedList<Integer> values = (LinkedList<Integer>) sl.values();
		for(int i = 0; i < 10; i++){
			assertTrue(values.contains(i));
		}
		sl.remove(5);
		values = (LinkedList<Integer>) sl.values();
		for(int i = 0; i < 10; i++){
			if(i == 5) assertFalse(values.contains(i));
			else assertTrue(values.contains(i));
		}
		sl.clear();
		values = (LinkedList<Integer>) sl.values();
		LinkedList<Integer> test = new LinkedList<Integer>();
		assertEquals(values, test);
	}

	@Test
	public void testRemove() {
		sl = createAddTen();
		assertEquals(sl.size(), 10);
		assertTrue(sl.containsKey(0));
		assertTrue(sl.containsValue(0));
		sl.remove(0);
		assertEquals(sl.size(), 9);
		assertFalse(sl.containsKey(0));
		assertFalse(sl.containsValue(0));	
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testRemoveNull(){
		sl = createAddOne();
		sl.remove(null);
	}
	
	@Test
	public void initTest(){
		sl = new SkipListMap<Integer, Integer>(new CoinFlipper());
		assertEquals(sl.size(), 0);
		LinkedList<Integer> test = new LinkedList<Integer>();
		LinkedList<Integer> values = (LinkedList<Integer>) sl.values();
		assertEquals(test, values);
		TreeSet<Integer> set = (TreeSet<Integer>) sl.keySet();
		TreeSet<Integer> test2 = new TreeSet<Integer>();
		assertEquals(set, test2);
		assertEquals(null, sl.firstKey());
		assertEquals(null, sl.lastKey());
		assertEquals(null, sl.firstKey());
		assertEquals(null, sl.firstKey());
		assertEquals(null, sl.get(1));
		
		
	}
	
	public SkipListMap<Integer, Integer> createAddOne(){
		sl = new SkipListMap<Integer, Integer>(new CoinFlipper());
		sl.put(1, 1);
		return sl;	
	}
	
	public SkipListMap<Integer, Integer> createAddTen(){
		sl = new SkipListMap<Integer, Integer>(new CoinFlipper());
		for(int i = 0; i < 10; i++){
			sl.put(i, i);
		}
		return sl;	
	}
	
	public SkipListMap<Integer, Integer> createAddRandom(){
		sl = new SkipListMap<Integer, Integer>(new CoinFlipper());
		for(int i = 0; i < (int)(Math.random() * 100); i++){
			sl.put((int)(i * Math.random()), (int)(i * Math.random()));
		}
		return sl;	
	}

}
